#include <iostream>
#include <string>
#include <cstring>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

using std::string;
using std::cout;
using std::endl;

// // 模拟实现cat命令
// int main(int argc, char* argv[])
// {
//     if (argc != 2)
//     {
//         cout << "argv error" << endl;
//         exit(1);
//     }

//     FILE* fp = fopen(argv[1], "r");
//     if (fp == nullptr)
//     {
//         perror("fopen error");
//         exit(2);
//     }

//     // 打开后，按行读取
//     char line[64];
//     while (fgets(line, sizeof(line), fp) != nullptr)
//     {
//         cout << line;
//     }

//     fclose(fp);
//     return 0;
// }


// // 熟悉一下c语言的写入接口
// int main(int argc, char* argv[])
// {
//     if (argc != 2)
//     {
//         cout << "argv error" << endl;
//         exit(1);
//     }

//     FILE* fp = fopen(argv[1], "w");
//     if (fp == nullptr)
//     {
//         perror("fopen error");
//         exit(2);
//     }

//     const char* s1 = "hello fwrite\n";
//     fwrite(s1, strlen(s1), 1, fp);

//     const char* s2 = "hello fprintf\n";
//     fprintf(fp, "%s", s2);

//     const char* s3 = "hello fputs\n";
//     fputs(s3, fp);

//     fclose(fp);
// }


// // 系统调用接口   open  read  write
// int main()
// {
//     umask(0); // 可以把umask设置成0
//     int fd = open("log2.txt", O_CREAT | O_WRONLY | O_TRUNC, 0666);
//     if (fd < 0)
//     {
//         perror("open error");
//         exit(1);
//     }

//     char buffer[64];
//     memset(buffer, 0, sizeof(buffer));
//     std::cin >> buffer;
//     write(fd, buffer, strlen(buffer));

//     close(fd);

//     sleep(1);

//     int ip = open("log2.txt", O_RDONLY);
//     if (ip < 0)
//     {
//         perror("open error");
//         exit(1);
//     }
//     char buf[64];
//     memset(buf, 0, sizeof(buf));
//     ssize_t n =  read(ip, buf, sizeof(buf));
//     buf[n] = 0;
//     cout << buf << endl;

//     close(ip);
//     return 0;
// }


// // 输出重定向
// int main()
// {
//     close(1); // 关闭标准输出
//     int fp = open("log3.txt", O_CREAT | O_TRUNC  | O_WRONLY, 0666);
//     if (fp < 0)
//     {
//         perror("open error");
//         exit(1);
//     }

//     cout << "fp: "  << fp << endl;  // 此时 fp 应该为1  不过不会写在显示器上,而是写在文件中
//     cout << "fp: "  << fp << endl;
//     cout << "fp: "  << fp << endl;

//     fprintf(stdout, "hello fprintf\n");
//     fputs("hello fputs\n", stdout);
//     const char* s = "hello fwrite\n";
//     fwrite(s, strlen(s), 1,  stdout);
//     const char* s1 = "hello write\n";
//     write(fp, s1, strlen(s1));

//     fflush(stdout);

//     close(fp);
//     return 0;
// }


// // 输入重定向
// int main()
// {
//     close(0);
//     int fd = open("log4.txt", O_CREAT | O_RDONLY);
//     if (fd < 0)
//     {
//         perror("open error");
//         exit(1);
//     }

//     cout << "fd: " << fd << endl;

//     char buffer[64];
//     fgets(buffer, sizeof buffer, stdin);
//     cout << buffer <<endl;

//     close(fd);
// }


// 缓冲区在哪？ 谁提供？
// int main()
// {
//     // c接口   往显示器打印
//     printf("hello printf\n");
//     fprintf(stdout, "hello fprintf\n");
//     const char* s2 = "hello fputs\n";
//     fputs(s2, stdout);

//     // 系统接口
//     const char* s3 = "hello write\n";
//     write(1, s3, strlen(s3));
//     fork();
// }

int main()
{
    // c接口   往文件中打印 
    close(1);
    int fd = open("log4.txt", O_WRONLY | O_TRUNC);
    if (fd < 0)
    {
        perror("open error");
        exit(1);
    }

    printf("hello printf\n");
    fprintf(stdout, "hello fprintf\n");
    const char* s = "hello fputs\n";
    fputs(s, stdout);

    // 系统接口
    const char* s1 = "hello write\n";
    write(1, s1, strlen(s1));

    fork();  // 和fork有关，系统接口打印了一次，但是c接口打印了两次  那么缓冲区绝对不是由OS提供的
    // 往显示器打印，使用的是行刷新设备， 出现\n，就会刷新，当执行到fork时，缓冲区中的数据已经被刷新出来了，fork没有意义了
    // 往文件中打印，使用的全刷新设备，使用\n，没有意义，它是等写满了缓冲区才会刷新，而系统接口是直接会把数据给OS，
    //      使用c接口就会把数据先放在缓冲区中，这样fork之后，进程退出，缓冲区的数据强制被刷新，由于写时拷贝会把数据拷贝一份
    //      因此，C接口的数据会被打印两次
    // 所有的设备，永远倾向于全缓冲 -- 需要更少此的IO操作，更少的外设访问，提高效率
    return 0;
}

